# include <stdio.h>

#define NOFFMAGIC	0xbadfad 

typedef struct segment {
  int virtualAddr;
  int inFileAddr;
  int size;
} Segment;

typedef struct noffHeader {
   int noffMagic;
   Segment code;
   Segment initData;
   Segment uninitData;
} NoffHeader;

int main(int argc, char *argv[])
{
	FILE *bin;
	int ins;
	int pc=0;
	NoffHeader nh;

	if (argc<2) {
		printf("Usage: \"%s\" <executable>.\n", argv[0]);
		exit(-1);
	}
	
	bin=fopen(argv[1], "rb");
	if (bin==NULL) {
		printf("File \"%s\" not found.\n", argv[1]);
		exit(-1);
	}

	if (fread((void *)&nh, sizeof(NoffHeader), 1, bin)<1) {
		printf("NOFF Header not found! \"%s\" is not a NOFF file.\n", argv[1]);
		exit(-1);
	}

	if (nh.noffMagic!=NOFFMAGIC) {
		printf("NOFF MAGIC error! \"%s\" is not a NOFF file.\n", argv[1]);
		exit(-1);
	}

	printf("Note that if segment size==0, addresses can be arbitrary\n");
	printf(".text Segment: Size=0x%04x, Virtual Address=0x%08x, In-file Address=0x%08x\n", 
		nh.code.size, nh.code.virtualAddr, nh.code.inFileAddr);
	printf(".data Segment: Size=0x%04x, Virtual Address=0x%08x, In-file Address=0x%08x\n", 
		nh.initData.size, nh.initData.virtualAddr, nh.initData.inFileAddr);
	printf(".bss  Segment: Size=0x%04x, Virtual Address=0x%08x, In-file Address=0x%08x\n", 
		nh.uninitData.size, nh.uninitData.virtualAddr, nh.uninitData.inFileAddr);

	printf("CODE----------------\n");
	while (!feof(bin)) {
		fread((void *)&ins, sizeof(int), 1, bin);
		if (ins==0)
			printf("0x%04x : %s\n", pc, "nop");
		else if (ins ==0x0c)
			printf("0x%04x : %s\n", pc, "syscall");
		else if ((ins & 0xfc000000) == 0x0c000000)
			printf("0x%04x : %s\t0x%x\n", pc, "jal", (ins&(~0xfc000000))<<2);
		else if ((ins & 0xfc000000) == 0x08000000)
			printf("0x%04x : %s\t0x%x\n", pc, "j", (ins&(~0xfc000000))<<2);
		else if ((ins & 0xfc000000) == 0x28000000)
			printf("0x%04x : %s\t$%d, $%d, 0x%x\n", pc, "slt", 
			(ins&(0x001f0000))>>16, (ins&0x03e00000)>>21, (ins&0x1f));
		else if ((ins & 0xfc000000) == 0x24000000) {
			if (ins&0x8000) 
				printf("0x%04x : %s\t$%d, $%d, 0x%x\n", pc, "subiu", 
				(ins&(0x001f0000))>>16, (ins&(0x03e00000))>>21, (0x10000-(ins&0xffff)));
			else
				printf("0x%04x : %s\t$%d, $%d, 0x%x\n", pc, "addiu", 
				(ins&(0x001f0000))>>16, (ins&(0x03e00000))>>21, (ins&0xffff));
		}
		else if ((ins & ~0x03e00008)==0)
			printf("0x%04x : %s\t$%d\n", pc, "j", (ins&(0x03e00000))>>21);
		else if ((ins & ~0x03e0f821)==0)
			printf("0x%04x : %s\t$%d, $%d\n", pc, "mov", (ins&(0x0000f800))>>11, 
			(ins&(0x03e00000))>>21);
		else if ((ins & 0xfc000000)==0xac000000) {
			if (ins&0x8000) 
				printf("0x%04x : %s\t$%d, -%d($%d)\n", pc, "sw", (ins&(0x001f0000))>>16, 
				(0x10000 - (ins & 0xffff)), (ins&(0x03e00000))>>21);
			else
				printf("0x%04x : %s\t$%d, %d($%d)\n", pc, "sw", (ins&(0x001f0000))>>16, 
				(ins & 0xffff), (ins&(0x03e00000))>>21);
		}
		else if ((ins & 0xfc000000)==0xa0000000) {
			if (ins&0x8000) 
				printf("0x%04x : %s\t$%d, -%d($%d)\n", pc, "sb", (ins&(0x001f0000))>>16, 
				(0x10000 - (ins & 0xffff)), (ins&(0x03e00000))>>21);
			else
				printf("0x%04x : %s\t$%d, %d($%d)\n", pc, "sb", (ins&(0x001f0000))>>16, 
				(ins & 0xffff), (ins&(0x03e00000))>>21);
		}
		else if ((ins & 0xfc000000)==0x8c000000) {
			if (ins&0x8000) 
				printf("0x%04x : %s\t$%d, -%d($%d)\n", pc, "lw", (ins&(0x001f0000))>>16, 
				(0x10000 - (ins & 0xffff)), (ins&(0x03e00000))>>21);
			else
				printf("0x%04x : %s\t$%d, %d($%d)\n", pc, "lw", (ins&(0x001f0000))>>16, 
				(ins & 0xffff), (ins&(0x03e00000))>>21);
		}
		else if ((ins & 0xfc000000)==0x80000000) {
			if (ins&0x8000) 
				printf("0x%04x : %s\t$%d, -%d($%d)\n", pc, "lb", (ins&(0x001f0000))>>16, 
				(0x10000 - (ins & 0xffff)), (ins&(0x03e00000))>>21);
			else
				printf("0x%04x : %s\t$%d, %d($%d)\n", pc, "lb", (ins&(0x001f0000))>>16, 
				(ins & 0xffff), (ins&(0x03e00000))>>21);
		}
		else if ((ins & ~0x03fff821)==0) {
			printf("0x%04x : %s\t$%d, $%d, $%d\n", pc, "addu", 
			(ins&(0xf800))>>11, (ins&(0x03e00000))>>21, (ins&0x001f0000)>>16);
		}
		else if (ins & 0x10000000) { /* assuming branch */
			char *sins;
			int tar=ins & 0xffff;

			if (tar & 0x8000)
				tar=-(0x10000-tar);
			tar*=4;
			tar+=pc+4;
			if ((ins & 0xfc000000)==0x18000000) 
				sins="blez";
			else if ((ins & 0xfc000000)==0x14000000) 
				sins="bne";
			/**else if ((ins & 0xfc000000)==0x3c000000) 
				sins="be?"; **/
			else {
				sins="bxxx";
				printf("ins=0x%08x\n",ins);
			}
			printf("0x%04x : %s\t$%d, $%d, 0x%x\n", pc, sins, 
			(ins&(0x03e00000))>>21, (ins&(0x001f0000))>>16, tar);
		}
		else if ((ins & ~0x001fffc0) == 0)
			printf("0x%04x : %s\t$%d, $%d, 0x%x\n", pc, "sll", 
			(ins&0x0000f800)>>11, (ins&(0x001f0000))>>16, (ins&0x7c0)>>6);
		else if ((ins & ~0xf812) == 0)
			printf("0x%04x : %s\t$%d\n", pc, "mflo?", (ins&0x0000f800)>>11);
		else if ((ins & ~0x03ff0018) == 0)
			printf("0x%04x : %s\t$%d, $%d\n", pc, "mult?", (ins&0x03e00000)>>21,
 			(ins&0x001f0000)>>16);
		else 
			printf("0x%04x : 0x%08x /* not recognized yet */\n", pc, ins);
		pc+=4;
	}
}
